﻿using System.Reflection;

namespace _01单例模式.反射破坏单例模式
{

    /// <summary>
    /// 通过定义局部变量标识来解决反射创建对象的问题，只有第一次反射创建对象会成功；缺点是通过反射也可以改变局部变量_isOk的值。
    /// </summary>
    public class SingleLayMan4
    {
        //2、声明静态字段  存储我们唯一的对象实例
        private volatile static SingleLayMan4? _singleLayMan;
        private static object _oj = new object();
        private static bool _isOk = false;
        //私有化构造函数
        private SingleLayMan4()
        {
            lock (_oj)
            {
                if (_isOk == false)
                {
                    _isOk = true;
                }
                else
                {
                    throw new Exception("不要通过反射来创建对像！只有第一次通过反射创建对象会成功！请做第一个吃葡萄的人！");
                }
            }
        }

        /// <summary>
        /// //解决多线程安全问题，双重锁定，减少系统消耗，节约资源
        /// </summary>
        public static SingleLayMan4 GetSingleLayMan()
        {
            if (_singleLayMan == null)
            {
                lock (_oj)
                {
                    if (_singleLayMan == null)
                    {
                        _singleLayMan = new SingleLayMan4();
                        Console.WriteLine("我被创建了一次！");
                    }
                }
            }           
            return _singleLayMan;
        }
       
    }

    public class SingleLayManTest4
    {
        /// <summary>
        /// 第一次创建对象会成功，因为执行构造函数时没有执行GetSingleLayMan()，跨过了new，导致_isOk赋值true，第二次反射创建执行构造函数时判断变量_isOk为true，走入异常逻辑
        /// </summary>
        public static void FactTestReflection()
        {
            //第一次创建对象会成功
            var singleLayMan1 = GetReflectionSingleLayMan4Instance();

            //第二次创建对象会失败，报异常
           var singleLayMan2 = GetReflectionSingleLayMan4Instance();

            Console.WriteLine(singleLayMan1.GetHashCode());
        }
        private static SingleLayMan4 GetReflectionSingleLayMan4Instance()
        {
            var type = Type.GetType("_01单例模式.反射破坏单例模式.SingleLayMan4");
            //获取私有的构造函数
            var ctors = type?.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);
            //执行构造函数
            SingleLayMan4 singleLayMan = (SingleLayMan4)ctors[0].Invoke(null);
            return singleLayMan;
        }

        /// <summary>
        /// 通过反射也可以改变局部变量_isOk的值,继续创建对象
        /// </summary>
        public static void FactTestReflection2()
        {
            Type type = Type.GetType("_01单例模式.反射破坏单例模式.SingleLayMan4");
            //获取私有的构造函数
            var ctors = type?.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);
            //执行构造函数
            SingleLayMan4 singleLayMan1 = (SingleLayMan4)ctors[0].Invoke(null);
            FieldInfo fieldInfo =  type.GetField("_isOk", BindingFlags.NonPublic | BindingFlags.Static);
            fieldInfo.SetValue("_isOk", false);
            SingleLayMan4 singleLayMan2 = (SingleLayMan4)ctors[0].Invoke(null);

            Console.WriteLine(singleLayMan1.GetHashCode());
            Console.WriteLine(singleLayMan2.GetHashCode());
        }
       
    }
}
